// Copyright Leonid Shlyapnikov 2010
// Distributed under the GNU Lesser General Public License http://www.gnu.org/licenses/lgpl.html
//    author: Leonid Shlyapnikov, created on: Jan 31, 2010

#ifndef FIXPARSER_CPP_SRC_MAIN_FIXPARSER_MEMORYAREA_H_
#define FIXPARSER_CPP_SRC_MAIN_FIXPARSER_MEMORYAREA_H_

#include <boost/exception/all.hpp>
#include <boost/utility.hpp>
#include <exception>
#include <string>

#include "./log.h"


namespace fixparser {

class MemoryAreaBadAlloc: public std::bad_alloc {
public:
    explicit MemoryAreaBadAlloc(const std::string& error): error_(error) {
    }

    virtual ~MemoryAreaBadAlloc() throw() { // bad_alloc requires
    }

    virtual const char* what() const throw() { // bad_alloc requires
        return this->error_.c_str();
    }
private:
    const std::string error_;
};

class MemoryArea: public boost::noncopyable {
public:
    explicit MemoryArea(size_t capacity);
    virtual ~MemoryArea();

    void* allocate(size_t size); // throws std::bad_alloc

    template<typename T>
    T* allocate(size_t size); // throws std::bad_alloc

    void assert_contains(const void* pointer) const;
    bool contains(const void* pointer) const;

    void reset();
    size_t capacity() const { return this->capacity_; }
    size_t size() const { return this->size_; }

    template<typename T>
    T* create() { // throws std::bad_alloc
        const size_t requestedSize = sizeof(T);
        void* buffer = this->allocate(requestedSize);
        if (0 == buffer) {
            LOG_ERROR("Not enough capacity in the " << this->to_string() << ", requested size: " << requestedSize);
            BOOST_THROW_EXCEPTION(std::bad_alloc());
        }

        // placement with a global operator new
        return ::new(buffer) T(this);
    }

    std::string to_string() const;

private:
    const size_t capacity_;
    size_t size_;
    char* bytes_;
};

}

#endif  // FIXPARSER_CPP_SRC_MAIN_FIXPARSER_MEMORYAREA_H_
